/******************************************************************************
 * Filename: main.c
 * Author: hucj
 * Created Time: 2023-06-28
 * Description: 智慧燃气项目，计算卧式储气罐的液位与体积容量的对应关系
 * 修改记录 2024-07-05 :
 *     添加 200立方卧式储罐的容量计算公式
 *     最新国标 NB/T 47001 2023 ：https://www.doc88.com/p-77447987850607.html
 * 修改记录 2024-09-02 : 新增 5立方米储存罐计算公式，参考国标 [NB/T 47001 2009]
 *****************************************************************************/

#include <stdio.h>
#include <math.h>
#include <windows.h>
#include <stdint.h>

static const double PI = 3.1415926;
static FILE* gas_file = NULL;

///////////////////////////////////////////////////////////////////////////////////////////

// 公式一：https://blog.csdn.net/weixin_45632511/article/details/129580638
// 参数说明: r为圆筒半径, hi为椭球封头短半轴长度, hl为液位高度(hl取值范围是[0, 2r]), L为储罐圆柱段长度, 单位均为m
double calcTankCap1(double hi, double r, double hl, double L)
{
    if (hl > 2 * r) {
        hl = 2 * r;
    }

    double V1, V2, V;
    double h = hl - r; // h取值范围是[-r, r],储罐中轴线处h=0

    V1 = PI * hi * (r*r*h - pow(h, 3) / 3 + 2 * pow(r, 3) / 3) / r;
    V2 = L * r * r *(asin(h / r) + h * sqrt(r*r - h * h) / (r*r) + PI / 2);
    V = V1 + V2;

    return V;
}

// 公式二：https://www.23bei.com/tool/521.html
// 参数说明: r为圆筒半径, hi为椭球封头短半轴长度, hl为液位高度(hl取值范围是[0, 2r]), L为储罐圆柱段长度, 单位均为m
double calcTankCap2(double hi, double r, double hl, double L)
{
    if (hl > 2 * r) {
        hl = 2 * r;
    }

    double V;

    double roundS = (PI * r * r / 2) - ( (r - hl) * sqrt(2*r*hl - hl*hl)) - r*r*asin((r - hl)/r);
    double ellipsoid = ((PI * hi) / (3 * r)) * (3 * r*r*hl - pow(r, 3) + pow(r-hl, 3));

    V = L * roundS + ellipsoid;

    return V;
}

// 公式三: https://patentimages.storage.googleapis.com/b3/51/67/33d0405b709274/CN109029565A.pdf
// 参数说明: r为圆筒半径, hi为椭球封头短半轴长度, hl为液位高度(hl取值范围是[0, 2r]), L为储罐圆柱段长度, 单位均为m
double calcTankCap3(double hi, double r, double hl, double L)
{
    if (hl > 2 * r) {
        hl = 2 * r;
    }

    double V;

    V = L * (hl - r) * sqrt(hl * (2 * r - hl))
            + 2 * L * r * r * asin(sqrt(hl/(2 * r)))
            + (PI / 4) * r * r * hl
            - (PI / 12) * pow(hl - r, 3)
            - (PI / 12) * pow(r, 3);

    return V;
}

///////////////////////////////////////////////////////////////////////////////////////////
// 计算特定容量储罐的"液位-体积"对应关系表，自动生成xls表格文件

void calc5M3TankLiquidLevel()
{
    printf("5立方米储罐液位-体积对应关系计算:\n");
    fprintf(gas_file, "%s\n", "5立方米储罐液位-体积对照表 量程(0~1200mm)");
    fprintf(gas_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
            "M\\cm", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

    int h;
    for (h = 0; h <= 1200; h += 10) {
        if (h % 100 == 0) {
            printf("------------------------------------\n");

            fprintf(gas_file, "\n");
            double headMeter = (double)h / 1000;
            fprintf(gas_file, "%.2f\t", headMeter);
        }

        // 5立方米储罐参数设置(按国标规格 NB/T 47001-2009 5立方米卧式储罐设置)
        // 左右封头高度 0.3m, 圆筒半径 0.6m, 储罐圆柱长度L 4.0米, 时， 满容量为： 4.97628 立方米
        double hl = (double)h / 1000;
        double V = calcTankCap2(0.3, 0.6, hl, 4.0);
        fprintf(gas_file, "%.5f\t", V);
        printf("液位高度 = %.2f m, 体积容量 = %.5f m3\n", hl, V);
    }
}


void calc12M3TankLiquidLevel()
{
    printf("12立方米储罐液位-体积对应关系计算:\n");
    fprintf(gas_file, "%s\n", "12立方米储罐液位-体积对照表 量程(0~1800mm)");
    fprintf(gas_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
            "M\\cm", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

    int h;
    for (h = 0; h <= 1800; h += 10) {
        if (h % 100 == 0) {
            printf("------------------------------------\n");

            fprintf(gas_file, "\n");
            double headMeter = (double)h / 1000;
            fprintf(gas_file, "%.2f\t", headMeter);
        }

        // 12立方米储罐参数设置(无对应国标规格，按10立方储罐加长设置)：
        // 左右封头高度 0.45m, 圆筒半径 0.9m, 储罐圆柱长度L 4.1米, 时， 满容量为：11.96004 立方米
        double hl = (double)h / 1000;
        double V = calcTankCap2(0.45, 0.9, hl, 4.1);
        fprintf(gas_file, "%.5f\t", V);
        printf("液位高度 = %.2f m, 体积容量 = %.5f m3\n", hl, V);
    }
}

void calc32M3TankLiquidLevel()
{
    printf("32立方米储罐液位-体积对应关系计算:\n");
    fprintf(gas_file, "%s\n", "32立方米储罐液位-体积对照表 量程(0~2400mm)");
    fprintf(gas_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
            "M\\cm", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

    int h;
    for (h = 0; h <= 2400; h += 10) {
        if (h % 100 == 0) {
            printf("------------------------------------\n");

            fprintf(gas_file, "\n");
            double headMeter = (double)h / 1000;
            fprintf(gas_file, "%.2f\t", headMeter);
        }

        // 32立方米储罐参数设置(无对应国标规格，按30立方储罐加长设置)：
        // 左右封头高度 0.6m, 圆筒半径 1.2m, 储罐圆柱长度L=6.2米, 时， 满容量为：31.66725 立方米
        double hl = (double)h / 1000;
        double V = calcTankCap2(0.6, 1.2, hl, 6.2);
        fprintf(gas_file, "%.5f\t", V);
        printf("液位高度 = %.2f m, 体积容量 = %.5f m3\n", hl, V);
    }
}

void calc50M3TankLiquidLevel()
{
    printf("50立方米储罐液位-体积对应关系计算:\n");
    fprintf(gas_file, "%s\n", "50立方米储罐液位-体积对照表 量程(0~2800mm)");
    fprintf(gas_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
            "M\\cm", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

    int h;
    for (h = 0; h <= 2800; h += 10) {
        if (h % 100 == 0) {
            printf("------------------------------------\n");

            fprintf(gas_file, "\n");
            double headMeter = (double)h / 1000;
            fprintf(gas_file, "%.2f\t", headMeter);
        }

        // 50立方米储罐参数设置(按国标规格设置)：
        // 左右封头高度 0.7m, 圆筒半径 1.4m, 储罐圆柱长度 L=7.1米, 时， 满容量为：49.46542 立方米
        double hl = (double)h / 1000;
        double V = calcTankCap2(0.7, 1.4, hl, 7.1);
        fprintf(gas_file, "%.5f\t", V);
        printf("液位高度 = %.2f m, 体积容量 = %.5f m3\n", hl, V);
    }
}

void calc63M3TankLiquidLevel()
{
    printf("63立方米储罐液位-体积对应关系计算:\n");
    fprintf(gas_file, "%s\n", "63立方米储罐液位-体积对照表 量程(0~2800mm)");
    fprintf(gas_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
            "M\\cm", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

    int h;
    for (h = 0; h <= 2800; h += 10) {
        if (h % 100 == 0) {
            printf("------------------------------------\n");

            fprintf(gas_file, "\n");
            double headMeter = (double)h / 1000;
            fprintf(gas_file, "%.2f\t", headMeter);
        }

        // 63立方米储罐参数设置(无对应国标规格，按50立方储罐加长设置)：
        // 左右封头高度 0.7m, 圆筒半径 1.4m, 储罐圆柱长度 L=9.3米, 时， 满容量为：63.01197 立方米
        double hl = (double)h / 1000;
        double V = calcTankCap2(0.7, 1.4, hl, 9.3);
        fprintf(gas_file, "%.5f\t", V);
        printf("液位高度 = %.2f m, 体积容量 = %.5f m3\n", hl, V);
    }
}

void calc100M3TankLiquidLevel()
{
    printf("100立方米储罐液位-体积对应关系计算:\n");
    fprintf(gas_file, "%s\n", "100立方米储罐液位-体积对照表 量程(0~3200mm)");
    fprintf(gas_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
            "M\\cm", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

    int h;
    for (h = 0; h <= 3200; h += 10) {
        if (h % 100 == 0) {
            printf("------------------------------------\n");

            fprintf(gas_file, "\n");
            double headMeter = (double)h / 1000;
            fprintf(gas_file, "%.2f\t", headMeter);
        }

        // 50立方米储罐参数设置(按国标规格设置)：
        // 左右封头高度 0.8m, 圆筒半径 1.6m, 储罐圆柱长度 L=11.3米, 时， 满容量为：99.45863 立方米
        double hl = (double)h / 1000;
        double V = calcTankCap2(0.8, 1.6, hl, 11.3);
        fprintf(gas_file, "%.5f\t", V);
        printf("液位高度 = %.2f m, 体积容量 = %.5f m3\n", hl, V);
    }
}


void calc200M3TankLiquidLevel()
{
    printf("200立方米储罐液位-体积对应关系计算:\n");
    fprintf(gas_file, "%s\n", "200立方米储罐液位-体积对照表 量程(0~3800mm)");
    fprintf(gas_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
            "M\\cm", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

    int h;
    for (h = 0; h <= 3800; h += 10) {
        if (h % 100 == 0) {
            printf("------------------------------------\n");

            fprintf(gas_file, "\n");
            double headMeter = (double)h / 1000;
            fprintf(gas_file, "%.2f\t", headMeter);
        }

        // 200立方米储罐参数设置(按国标规格设置)：
        // 左右封头高度 0.87m, 圆筒半径 1.9m, 储罐圆柱长度 L=16.3米, 时， 满容量为：198.03159 立方米
        double hl = (double)h / 1000.0f;
        double V = calcTankCap2(1.0f, 1.9f, hl, 16.3f);
        fprintf(gas_file, "%.5f\t", V);
        printf("液位高度 = %.2f m, 体积容量 = %.5f m3\n", hl, V);
    }
}

#if 0
uint32_t createExcel(void)
{

    gas_file = fopen("C:\\Users\\42984\\Desktop\\gasCalcTest.xls", "w+"); //二进制写入

    if (gas_file == NULL)
    {
        printf("gas_file is fail\n");
        return -1;
    }

    fprintf(gas_file, "%s\t%s\t%s\t%s\n", "姓名", "性别", "年龄", "体重");
    fprintf(gas_file, "%s\t%s\t%d\t%lf\n", "阿呆", "男", 18, 62.5);
    fclose(gas_file);
    return 0;
}
#endif


// 参数说明: r为圆筒半径, hi为椭球封头短半轴长度, hl为液位高度(hl取值范围是[0, 2r]), L为储罐圆柱段长度, 单位均为m
// double calcTankCap3(double hi, double r, double hl, double L)

// double calculate_volume(double D, double L, double h) {
//     double r = D / 2;
//     double H = D - h;
//     double theta = acos((r - h) / r);
//     double S = pow(r, 2) * theta;
//     double x = r * sin(theta);
//     double A = (S - x * H) * L;
//
//     return A;
// }

double calculate_volume(double D, double L, double h)
{
    double r = D / 2;
    double b = D / 4; // 短轴半径
    double cylinder_volume = L * M_PI * pow(h, 2); // 圆柱体部分的体积
    double theta = acos((r - h) / r);
    double ellipsoid_volume = 2 * (pow(r, 2) * b * theta - (r - h) * sqrt(2 * r * h - pow(h, 2)) * b) / 3; // 椭球封头部分的体积

    return cylinder_volume + ellipsoid_volume;
}

int main()
{
    SetConsoleOutputCP(CP_UTF8);

    // 三个公式计算对比
    double highLevel = 1.20;
    printf("1 LLV=%lf m, V = %lf\n", highLevel, calcTankCap1(0.6, 1.2, highLevel, 6.2)); // 公式1计算
    printf("2 LLV=%lf m, V = %lf\n", highLevel, calcTankCap2(0.6, 1.2, highLevel, 6.2)); // 公式2计算
    printf("3 LLV=%lf m, V = %lf\n", highLevel, calcTankCap3(0.6, 1.2, highLevel, 6.2)); // 公式3计算
    printf("4 LLV=%lf m, V = %lf\n", highLevel, calculate_volume(2.4, 6.2, highLevel)); // 公式4计算


    if (fopen_s(&gas_file, "C:\\Users\\42984\\Desktop\\gasCalcTest.xls", "w+") == 0) {
        if (gas_file == NULL) {
            printf("gas_file is fail\n");
            return -1;
        }

        calc5M3TankLiquidLevel();
        // calc12M3TankLiquidLevel();
        // calc32M3TankLiquidLevel();
        // calc50M3TankLiquidLevel();
        // calc63M3TankLiquidLevel();
        // calc100M3TankLiquidLevel();
        // calc200M3TankLiquidLevel();

        fclose(gas_file);
    }
    else {
    }

    return 0;
}
